package cn.scy.business.service.xiamdx;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.scy.base.PageResult;
import cn.scy.business.domain.entity.NumMemberInfo;
import cn.scy.business.domain.entity.xiamdx.XiamdxNumberInfo;
import cn.scy.business.domain.entity.xiamdx.XiamdxReportInfo;
import cn.scy.business.domain.param.guangzlt.NotifyCustomerReq;
import cn.scy.business.domain.param.xiamdx.XiamdxNotifyCustomerReq;
import cn.scy.business.domain.param.xiamdx.XiamdxNumberInfoBatchParam;
import cn.scy.business.domain.param.xiamdx.XiamdxNumberInfoParam;
import cn.scy.business.domain.param.xiamdx.XiamdxRealAuthRequestDto;
import cn.scy.business.domain.vo.NotifyResult;
import cn.scy.business.mapper.xiamdx.XiamdxNumberInfoMapper;
import cn.scy.business.mapper.xiamdx.XiamdxReportInfoMapper;
import cn.scy.business.service.NumMemberInfoService;
import cn.scy.constant.BusinessConst;
import cn.scy.exception.BusinessException;
import cn.scy.util.PageUtil;
import cn.scy.util.Sm4Util;
import cn.scy.util.xiamdx.AESGCMUtil;
import cn.scy.util.xiamdx.MD5;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报备管理-号码表 服务实现类
 *
 * @author scy
 * @since 2025-04-27
 */
@Service
public class XiamdxNumberInfoServiceImpl extends ServiceImpl<XiamdxNumberInfoMapper, XiamdxNumberInfo> implements XiamdxNumberInfoService {

    private static final Log LOGGER = Log.get();

    @Resource
    private NumMemberInfoService memberInfoService;

    @Resource
    private XiamdxReportInfoMapper reportInfoMapper;

    @Value("${xiamdxReport.appId}")
    private String appId;

    @Value("${xiamdxReport.appSecect}")
    private String appSecect;

    @Value("${xiamdxReport.apiUrl}")
    private String apiUrl;

    @Override
    public PageResult<XiamdxNumberInfo> listPage(XiamdxNumberInfoParam param) {
        // 构建分页对象
        Page<XiamdxNumberInfo> pageQuery = PageUtil.convert2PageQuery(param);
        // 构建查询参数对象
        LambdaQueryWrapper<XiamdxNumberInfo> query = new LambdaQueryWrapper<>();
        query.eq(StrUtil.isNotBlank(param.getMemberId()), XiamdxNumberInfo::getMemberId, param.getMemberId());
        query.like(StrUtil.isNotBlank(param.getPhoneNumber()), XiamdxNumberInfo::getPhoneNumber, param.getPhoneNumber());
        query.eq(ObjectUtil.isNotNull(param.getPhoneType()), XiamdxNumberInfo::getPhoneType, param.getPhoneType());
        query.eq(StrUtil.isNotBlank(param.getStatus()), XiamdxNumberInfo::getStatus, param.getStatus());
        query.orderByDesc(XiamdxNumberInfo::getCreateTime).orderByAsc(XiamdxNumberInfo::getId);
        // 执行查询
        Page<XiamdxNumberInfo> pageData = this.page(pageQuery, query);
        return PageUtil.convert2PageResult(pageData, pageData.getRecords());
    }

    @Override
    public XiamdxNumberInfo info(String id) {
        return this.getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addNumber(XiamdxNumberInfo numNumberInfo) {
        // 校验参数
        checkParam(numNumberInfo);
        // 保存数据
        return this.save(numNumberInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addNumberBatch(XiamdxNumberInfoBatchParam params) {
        if (ObjectUtil.isNull(params)) {
            throw new BusinessException("参数不能为空");
        }
        List<String> numbers = params.getNumbers();
        if (CollUtil.isEmpty(numbers)) {
            throw new BusinessException("号码不能为空");
        }
        // 号码去重
        numbers = CollUtil.distinct(numbers);
        // 校验数据
        List<XiamdxNumberInfo> list = CollUtil.newArrayList();
        numbers.forEach(phoneNumber -> {
            XiamdxNumberInfo num = new XiamdxNumberInfo();
            num.setMemberId(params.getMemberId());
            num.setPhoneNumber(phoneNumber);
            num.setPhoneType(params.getPhoneType());
            checkParam(num);
            list.add(num);
        });
        // 保存数据
        return this.saveBatch(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editNumber(XiamdxNumberInfo numNumberInfo) {
        // 校验参数
        checkParam(numNumberInfo);
        // 更新数据
        return this.updateById(numNumberInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteNumber(String id) {
        // 删除数据
        return this.removeById(id);
    }

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public Boolean report(XiamdxReportInfo numReportInfo) {
        XiamdxNumberInfo numberInfo = this.getById(numReportInfo.getNumberId());
        // 校验参数
        checkNum(numReportInfo, numberInfo);
        NumMemberInfo memberInfo = memberInfoService.getById(numberInfo.getMemberId());

        // 新增请求记录
        numReportInfo.setPhoneNumber(numberInfo.getPhoneNumber());
        reportInfoMapper.insert(numReportInfo);

        // 准备参数
        Long timeStamp = System.currentTimeMillis() / 1000;
        int status = 200;
        String msg = null;
        String resultCode =null;
        try{
            XiamdxRealAuthRequestDto dto = XiamdxRealAuthRequestDto.builder()
                    .name(AESGCMUtil.encrypt(memberInfo.getName(), appSecect))
                    .appId(appId)
                    .photo(AESGCMUtil.encrypt(memberInfo.getLiveFaceImage(),appSecect))
                    .identifyCardNO(AESGCMUtil.encrypt(memberInfo.getIdentityCard(), appSecect))
                    .requestId(IdUtil.simpleUUID())
                    .timestamp(timeStamp)
                    .certificateType("1")
                    .phoneNo(AESGCMUtil.encrypt(numberInfo.getPhoneNumber(), appSecect))
                    .build();
            String jsonData = JSONUtil.toJsonStr(dto);
            LOGGER.info("Xiamdx-请求体 " + jsonData);
            String signature = MD5.makeMD5(String.valueOf(timeStamp),appSecect,jsonData);
            String Auth = generateAuthorization(appId,String.valueOf(timeStamp),signature);
            LOGGER.info("Xiamdx-Authorization"+Auth);
            HttpResponse response = HttpRequest.post(apiUrl)
                    .header("Authorization", Auth)  // 设置 Authorization 头
                    .header("Content-Type", "application/json")   // 设置 Content-Type
                    .body(jsonData)  // 设置请求体
                    .timeout(3000000)  // 设置超时时间，单位毫秒
                    .execute();
            LOGGER.info(numberInfo.getPhoneNumber()+" -Xiamdx-响应体 " + response.getStatus()+response.body());
            if(response.getStatus() == 200){
                LOGGER.info(response.body());
            }

            // 解析响应
            JSONObject postResultJson = JSONObject.parseObject(response.body());
            msg = postResultJson.getString("resultMsg");
            resultCode = postResultJson.getString("resultCode");
            status = response.getStatus();
        }catch (Exception e){
            e.printStackTrace();
        }

        if (ObjectUtil.equals(200, status)) {

            // 更新报备记录
            numReportInfo.setReportStatus(BusinessConst.REPORT_SUCCESS);
            numReportInfo.setNotifyStatus(resultCode);
            numReportInfo.setNotifyFailReason(msg);
            reportInfoMapper.updateById(numReportInfo);
            if(!resultCode.equals("0")){
                throw new BusinessException(msg);
            }
            // 更新号码状态为待核验
            numberInfo.setStatus("1");
            this.updateById(numberInfo);
            return true;
        } else {
            throw new BusinessException("Xiamdx-"+ msg + "，号码：" + numberInfo.getPhoneNumber() + "，报备操作：" + numReportInfo.getMethod());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> notifyReq(XiamdxNotifyCustomerReq req) {
        // 联通发来的核验结果
        LOGGER.info("接收到电信发来的核验结果：" + JSONObject.toJSONString(req));
        LOGGER.info("开始处理核验结果");
        Map<String, Object> response = new HashMap<>(2);

        String phoneNo = null;
        try{
            phoneNo = AESGCMUtil.decrypt(req.getPhoneNo(), appSecect);
        }catch (Exception e){
            e.printStackTrace();
        }
        XiamdxReportInfo numReportInfo = reportInfoMapper.selectOne(
                new LambdaQueryWrapper<XiamdxReportInfo>()
                        .eq(XiamdxReportInfo::getPhoneNumber, phoneNo)
                        .orderByDesc(XiamdxReportInfo::getCreateTime) // 按 createTime 降序排序
                        .last("LIMIT 1") // 限制结果只返回一条记录
        );

        if (ObjectUtil.isNull(numReportInfo)) {
            LOGGER.error("找不到对应的报备记录，phoneNo：" + phoneNo);
            response.put("code", 500);
            response.put("msg", "requestId 有误");
            return response;
        }
        XiamdxNotifyCustomerReq xreq = new XiamdxNotifyCustomerReq();
        BeanUtils.copyProperties(req,xreq);
        xreq.setPhoneNo(phoneNo);
        // 更新号码状态和报备记录等本地数据
        updateLocalInfo(xreq, numReportInfo);
        response.put("code", 200);
        response.put("msg", "核验结果接收成功");
        LOGGER.info("核验结果处理完成");
        return response;
    }

    private void updateLocalInfo(XiamdxNotifyCustomerReq xreq, XiamdxReportInfo numReportInfo) {
        // 更新号码状态
        XiamdxNumberInfo number = this.getById(numReportInfo.getNumberId());
        if (StrUtil.equals(xreq.getCode(),"0")) {
            if (StrUtil.equals(numReportInfo.getMethod(), "append")) {
                number.setStatus("2");
            }
            if (StrUtil.equals(numReportInfo.getMethod(), "delete")) {
                number.setStatus("4");
            }
        } else {
            if (StrUtil.equals(numReportInfo.getMethod(), "append")) {
                number.setStatus("3");
            }
            if (StrUtil.equals(numReportInfo.getMethod(), "delete")) {
                number.setStatus("5");
            }
            if (ObjectUtil.isNotNull(xreq.getFailureReason())) {
                if (StrUtil.equals(xreq.getFailureReason(), "1")) {
                    numReportInfo.setNotifyFailReason(xreq.getDesc()+",三要素核验失败");
                }else if (StrUtil.equals(xreq.getFailureReason(), "2")) {
                    numReportInfo.setNotifyFailReason(xreq.getDesc()+",人脸核验失败");
                }else if (StrUtil.equals(xreq.getFailureReason(), "4")) {
                    numReportInfo.setNotifyFailReason(xreq.getDesc()+",已过期");
                }else if (StrUtil.equals(xreq.getFailureReason(), "5")) {
                    numReportInfo.setNotifyFailReason(xreq.getDesc()+",其他原因失败");
                }else {
                    numReportInfo.setNotifyFailReason(xreq.getDesc()+",未知原因失败");
                }
            }

        }
        this.updateById(number);
        // 更新报备记录
        numReportInfo.setNotifyStatus(xreq.getCode());
        numReportInfo.setNotifyTime(DateUtil.date());
        reportInfoMapper.updateById(numReportInfo);
    }

    private void checkNum(XiamdxReportInfo numReportInfo, XiamdxNumberInfo numberInfo) {
        // 如果号码已经被报备，或者处于待核验状态下，则不允许再次报备
        String status = numberInfo.getStatus();
        if (StrUtil.equalsAny(status, "1", "2") && StrUtil.equals(numReportInfo.getMethod(), "append")) {
            throw new BusinessException("该号码已被追加或处于待核验状态，无法再次追加");
        }
        if (StrUtil.equalsAny(status, "1", "4") && StrUtil.equals(numReportInfo.getMethod(), "delete")) {
            throw new BusinessException("该号码已被删除或处于待核验状态，无法再次删除");
        }
    }

    private void checkParam(XiamdxNumberInfo numNumberInfo) {
        // 同一人名下不能有重复号码
        LambdaQueryWrapper<XiamdxNumberInfo> query = new LambdaQueryWrapper<>();
        query.eq(StrUtil.isNotBlank(numNumberInfo.getMemberId()), XiamdxNumberInfo::getMemberId, numNumberInfo.getMemberId());
        query.eq(StrUtil.isNotBlank(numNumberInfo.getPhoneNumber()), XiamdxNumberInfo::getPhoneNumber, numNumberInfo.getPhoneNumber());
        query.ne(StrUtil.isNotBlank(numNumberInfo.getId()), XiamdxNumberInfo::getId, numNumberInfo.getId());
        long count = this.count(query);
        if (ObjectUtil.isNotNull(count) && count > 0) {
            throw new BusinessException("同一人名下不能有重复号码，重复号码：" + numNumberInfo.getPhoneNumber());
        }
    }

    public static String generateAuthorization(String appId,String timestamp, String signature) {
        // 构造Authorization头
        return "EOPAUTH appId=\"" + appId + "\",timestamp=\"" + timestamp + "\",signature=\"" + signature + "\"";
    }

}
